Skip to content

[https://nvbugs/6480621][test] Revert to 60-second KV transfer timeout for GB300 DeepSeek V4 Pro disaggregated perf-sanity - #17137

Open
chienchunhung wants to merge 2 commits into
NVIDIA:mainfrom
chienchunhung:codex/nvbug-6480621-timeout-60s-ci
Open

[https://nvbugs/6480621][test] Revert to 60-second KV transfer timeout for GB300 DeepSeek V4 Pro disaggregated perf-sanity#17137
chienchunhung wants to merge 2 commits into
NVIDIA:mainfrom
chienchunhung:codex/nvbug-6480621-timeout-60s-ci

Conversation

@chienchunhung

@chienchunhung chienchunhung commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Change kv_transfer_timeout_ms from 600000 ms to 60000 ms for both GEN and CTX in the targeted GB300 DeepSeek V4 Pro disaggregated perf-sanity configuration.
  • Keep the Python NIXL transceiver and every other workload parameter unchanged.
  • Carry the [https://nvbugs/6480621][fix] Preserve KV ownership in disaggregated precheck #17223 Python-transceiver/precheck ownership and fidelity fixes as one squashed prerequisite commit, followed by the timeout-only commit.

Commit structure and merge order

Because the GitHub base is still main, the Files tab currently includes the squashed #17223 changes as well as this PR's two-line YAML change. Reviewers should review the prerequisite commit first and treat 1714136e as the timeout-only change.

Motivation and diagnosis

NVBug 6480621 reported KV-transfer request failures after the 60-second timeout under a high-concurrency GB300 DeepSeek V4 Pro disaggregated E2E workload.

Earlier CI attempts at 60 seconds failed in the synthetic cache_transceiver_precheck with byte mismatches before the real benchmark started:

Those failures were not 60-second request-deadline expirations. The exact target configuration also produced the same precheck byte-corruption symptom with a 600-second timeout in Main #2875, Post-Merge-2.

The common problem was the Python sender's one-second future wait slice being treated as block-all completion. The precheck could release and reuse source KV pages while a transfer was still nonterminal. #17223 fixes that ownership contract, propagates the real model/runtime into the precheck, and excludes the intentionally untransferred MTP reserve page from exact-boundary verification.

Validation

Local:

  • both CTX and GEN parse as kv_transfer_timeout_ms: 60000;
  • the current head tree is identical to the previously validated pre-squash tree at b7bd98a1049ad02eb335f86cb2cb64c057bb4495;
  • YAML/pre-commit validation and DCO sign-off are preserved;
  • focused ownership, wait-slice, precheck-configuration, and verification regressions are included in [https://nvbugs/6480621][fix] Preserve KV ownership in disaggregated precheck #17223.

Diagnostic run on the preceding stack revision:

Fresh targeted CI with test reuse disabled: PASSED

  • Validated pre-squash SHA: b7bd98a1049ad02eb335f86cb2cb64c057bb4495
  • Current post-squash head 1714136e4dbfbe2c4570067da6572d268a058997 has the identical tree; only the commit history was rewritten.
  • Parent L0 build #51530 completed SUCCESS: one target test passed, with zero failures or skips.
  • Exact stage: GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-2
  • The precheck used model_dir=/scratch.trt_llm_data/llm-models/DeepSeek-V4-Pro, kv_cache_manager=V2, and transceiver_runtime=PYTHON on all roles.
  • gen_0 passed all six combinations: three context peers × request lengths 1,024 and 7,408. Mismatch, transfer-error, and initialization-error counts were zero.
  • The real gen-only benchmark completed 180/180 requests with zero failures.
  • Bot result · Result archive

Post-squash CI:

  • PR_Github #63870 was triggered on the current head 1714136e with --disable-fail-fast.
  • This run is in progress; its result is not yet part of the validation claim above.

Target test:

perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb300_deepseek-v4-pro-fp4_8k1k_con180_ctx3_dep4_gen1_dep32_eplb384_mtp3_ccb-NIXL]

Interpretation and remaining scope

The fresh run validates the corrected precheck and the concurrency-180, 3-CTX-server gen-only CI proxy at the original 60-second request deadline.

It does not prove that the original NVBug workload is resolved:

  • Original report: agentperf E2E, 8 CTX workers × 4 GPUs, 1 GEN worker × 32 GPUs, concurrency 1760
  • CI proxy: gen-only, 3 CTX workers × 4 GPUs, 1 GEN worker × 32 GPUs, concurrency 180

Before closing NVBug 6480621, the reporter should rerun the original or an equivalently stressful E2E workload at 60 seconds, preferably more than once.

Review and merge readiness

This PR is ready for stacked/dependent review after or alongside #17223. Both PRs are currently non-draft.

It is not yet merge-ready:

  • [https://nvbugs/6480621][fix] Preserve KV ownership in disaggregated precheck #17223 has not landed, so this PR temporarily carries its changes in the squashed prerequisite commit efe60576;
  • #51530 validated the exact current tree before the history rewrite, while post-squash CI #63870 is still in progress;
  • #51530 was a targeted partial-stage run. Its underlying L0 and target stage succeeded, but the partial run does not replace the final merge-gate CI.

Before merging:

  1. review and land [https://nvbugs/6480621][fix] Preserve KV ownership in disaggregated precheck #17223;
  2. rebase this PR onto the resulting main, drop efe60576, and confirm that its remaining diff is only the two timeout values;
  3. rerun the exact target stage with test reuse disabled on the final SHA; and
  4. run the normal full PR CI merge gate.

The timeout change may be merged as a scoped CI-policy/test change once those conditions are satisfied, without claiming NVBug 6480621 closed.

Dev Engineer Review

  • Reduced kv_transfer_timeout_ms from 600000 to 60000 for GEN and CTX in the targeted GB300 DeepSeek V4 Pro configuration.
  • Preserved KV-page ownership until confirmed transfer completion.
  • Added handling for failed, cancelled, missing, incomplete, and setup-error transfers.
  • Added model-root propagation and shell-safe LLM_MODELS_ROOT export.
  • Updated TxSession.wait_complete to retry until completion or failure.
  • Added fail-fast KV-cache-manager resolution checks.
  • Limited KV verification to the requested prompt range.
  • Updated context-transfer logging and documentation.
  • Limited configuration changes to the targeted workload.
  • No test-list files were modified.
  • The parent PR must land before restacking and final merge-gate validation.

QA Engineer Review

Test-code changes include:

  • Added exact-block-boundary coverage with MTP draft-token reservations.
  • Added bounded-polling coverage for retries, cancellation, task failures, auxiliary-task failures, missing auxiliary tasks, and cleanup.
  • Added configuration-resolution and shell-quoting tests.
  • Added precheck tests for speculative-page exclusion and transfer ownership.
  • Added transfer failure-path tests.
  • Added extract_pytest_command_env tests for quoted values, spaces, = characters, missing assignments, and malformed exports.
  • Removed test_tx_session_wait_complete_defaults_to_blocking.
  • No corresponding test-db/ or qa/ entries were added or modified, so these tests are not listed there.
  • Targeted CI passed with test reuse disabled. The precheck passed all six combinations, and the GEN benchmark completed 180/180 requests.
  • Verdict: sufficient for targeted validation. The original concurrency-1760, 8-CTX-worker NVBug workload remains unvalidated.

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --stage-list "GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-2"

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --disable-reuse-test --stage-list "GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-2"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63105 [ run ] triggered by Bot. Commit: 38ca970 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63106 [ run ] triggered by Bot. Commit: 38ca970 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63105 [ run ] completed with state ABORTED. Commit: 38ca970

Link to invocation

@chienchunhung chienchunhung changed the title [https://nvbugs/6480621][test] Validate 60-second KV transfer timeout [https://nvbugs/6480621][test] Revert to 60-second KV transfer timeout for GB300 DeepSeek V4 Pro disaggregated perf-sanity Jul 31, 2026
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63106 [ run ] completed with state SUCCESS. Commit: 38ca970
/LLM/main/L0_MergeRequest_PR pipeline #51197 (Partly Tested) completed with status: 'SUCCESS'

CI Report

Link to invocation

@chienchunhung

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --disable-reuse-test --stage-list "GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-1"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63144 [ run ] triggered by Bot. Commit: 38ca970 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63144 [ run ] completed with state FAILURE. Commit: 38ca970
/LLM/main/L0_MergeRequest_PR pipeline #51231 (Partly Tested) completed with status: 'ABORTED'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

Link to invocation

@chienchunhung

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --disable-reuse-test --stage-list "GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-1"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63150 [ run ] triggered by Bot. Commit: 38ca970 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63150 [ run ] completed with state FAILURE. Commit: 38ca970
/LLM/main/L0_MergeRequest_PR pipeline #51234 (Partly Tested) completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@chienchunhung

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --disable-reuse-test --stage-list "GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-1"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63165 [ run ] triggered by Bot. Commit: 38ca970 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63165 [ run ] completed with state FAILURE. Commit: 38ca970
/LLM/main/L0_MergeRequest_PR pipeline #51249 (Partly Tested) completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@chienchunhung

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --disable-reuse-test --stage-list "GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-1"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63555 [ run ] triggered by Bot. Commit: 3e6c120 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63555 [ run ] completed with state SUCCESS. Commit: 3e6c120
/LLM/main/L0_MergeRequest_PR pipeline #51521 (Partly Tested) completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@chienchunhung
chienchunhung force-pushed the codex/nvbug-6480621-timeout-60s-ci branch from 3e6c120 to b7bd98a Compare August 3, 2026 21:40
@chienchunhung

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --disable-reuse-test --stage-list "GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-2"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63564 [ run ] triggered by Bot. Commit: b7bd98a Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63564 [ run ] completed with state SUCCESS. Commit: b7bd98a
/LLM/main/L0_MergeRequest_PR pipeline #51530 (Partly Tested) completed with status: 'SUCCESS'

CI Report

Link to invocation

@chienchunhung
chienchunhung marked this pull request as ready for review August 3, 2026 23:41
@chienchunhung
chienchunhung requested review from a team as code owners August 3, 2026 23:41
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The changes forward LLM_MODELS_ROOT, enforce automatic KV-manager resolution, retry disaggregated transfer waits, preserve KV ownership until successful completion, exclude speculative pages from verification, and add focused unit and end-to-end coverage.

Changes

Disaggregated precheck transfer

Layer / File(s) Summary
Launch configuration and model-root forwarding
jenkins/scripts/perf/..., tests/scripts/perf-sanity/cache_transceiver_precheck/*, tests/unittest/others/test_cache_transceiver_precheck_config.py, tests/unittest/scripts/test_perf_submit.py
The submit scripts parse and forward LLM_MODELS_ROOT. Generated commands quote the value safely. Automatic KV-manager resolution now raises errors when model resolution fails.
Transfer wait and terminal-status handling
tensorrt_llm/_torch/disaggregation/*, tests/unittest/disaggregated/test_transceiver_bounded_polling.py
TxSession.wait_complete retries wait slices and returns terminal success or failure states. Cancellation, task failures, and missing auxiliary tasks remain distinct.
Precheck ownership and boundary validation
tests/scripts/perf-sanity/cache_transceiver_precheck/run_precheck.py, tests/unittest/others/test_cache_transceiver_precheck_run.py, tests/unittest/disaggregated/test_cache_transceiver_precheck_e2e.py, tests/scripts/perf-sanity/disaggregated/*.yaml
Precheck verification excludes speculative pages. Context and generation allocations remain owned until transfers complete successfully. Tests cover failure states, exact block boundaries, MTP settings, and updated transfer intervals.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SubmitScript
  participant PrecheckConfig
  participant PRECHECK
  participant TxSession
  participant KVPages
  SubmitScript->>PrecheckConfig: pass LLM_MODELS_ROOT
  PrecheckConfig->>PRECHECK: export model root and configure manager
  PRECHECK->>TxSession: submit and poll transfer wave
  TxSession-->>PRECHECK: completed, failed, cancelled, or pending status
  PRECHECK->>KVPages: release pages only after successful terminal status
Loading

Possibly related PRs

Suggested reviewers: bowenfu, nv-xtf, bo-nv

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes implement the linked issue’s ownership, wait handling, configuration, verification, and regression-test objectives for the disaggregated precheck.
Out of Scope Changes check ✅ Passed The code, tests, documentation, environment propagation, logging, and timeout changes support the linked precheck and NVBug objectives.
Title check ✅ Passed The title clearly identifies the ticket, change type, and primary timeout reduction for the targeted GB300 disaggregated perf-sanity configuration.
Description check ✅ Passed The description explains the change, motivation, validation, limitations, dependency on #17223, and remaining merge requirements in sufficient detail.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (5)
tests/scripts/perf-sanity/cache_transceiver_precheck/precheck_config.py (1)

132-139: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Annotate and document the shared launch-script interface.

precheck_prefix_lines is called by both submit modules. Add precise parameter and return annotations. Add Google-style Args and Returns sections that document llm_models_root and the generated export lines.

As per coding guidelines, “Annotate every function” and “Prefer docstrings for external interfaces, use Google-style docstrings, document public function arguments.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/scripts/perf-sanity/cache_transceiver_precheck/precheck_config.py`
around lines 132 - 139, Update precheck_prefix_lines with precise type
annotations for every parameter and its return value, and add a Google-style
docstring documenting all arguments—especially llm_models_root—and that the
function returns generated export lines. Keep the shared launch-script interface
behavior unchanged.

Source: Coding guidelines

tests/unittest/others/test_cache_transceiver_precheck_run.py (1)

380-397: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Clarify the two event lists.

_ctx_finish_runner binds its own list to free_events, and the test then overrides _free_all to append to the local events. The assertion free_events == [] therefore checks the discarded list. The test is correct, but the names invert the reader's expectation. Take the runner list as _ or drop the override and assert on the runner list only.

♻️ Proposed simplification
-def test_ctx_finish_wave_frees_only_after_block_all_returns_every_request(monkeypatch):
-    events = []
-
-    def check_status(at_least_request_num):
-        events.append(("block_all", at_least_request_num))
-        return [101, 102], []
-
-    runner, free_events = _ctx_finish_runner(monkeypatch, check_status)
+def test_ctx_finish_wave_frees_only_after_block_all_returns_every_request(monkeypatch):
+    calls = []
+
+    def check_status(at_least_request_num):
+        calls.append(("block_all", at_least_request_num))
+        return [101, 102], []
+
+    runner, events = _ctx_finish_runner(monkeypatch, check_status)
     reqs = {
     }
-    runner._free_all = lambda owned: events.append(("free", sorted(owned)))
 
     runner.ctx_finish_wave(reqs)
 
-    assert events == [("block_all", None), ("free", [0, 1])]
-    assert free_events == []
+    assert calls == [("block_all", None)]
+    assert events == [("free", [0, 1])]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/others/test_cache_transceiver_precheck_run.py` around lines
380 - 397, Clarify the event-list usage in
test_ctx_finish_wave_frees_only_after_block_all_returns_every_request by
discarding the unused free_events value from _ctx_finish_runner and asserting
the _free_all callback’s local events directly, or otherwise assert only the
runner-owned list without checking the discarded list.
tests/unittest/disaggregated/test_transceiver_bounded_polling.py (1)

421-428: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

This test does not reach the in-loop sibling check.

wait_complete calls has_failed() before the KV loop, so the pre-existing TaskStatus.ERROR on failed_task returns WaitResult.FAILED immediately. The assertions pending_task.wait_calls == [] confirm that. The test therefore duplicates test_tx_session_blocking_wait_treats_task_failure_as_terminal and leaves the sibling recheck at lines 1368-1371 of tensorrt_llm/_torch/disaggregation/native/transfer.py uncovered.

To cover that path, make the sibling fail during the first wait slice.

💚 Proposed test change to exercise the sibling recheck
 def test_tx_session_blocking_wait_detects_failed_sibling_behind_pending_task() -> None:
     pending_task = _FakeTask(TaskStatus.TRANSFERRING, wait_result=False)
-    failed_task = _FakeTask(TaskStatus.ERROR)
+    failed_task = _FakeTask(TaskStatus.TRANSFERRING, wait_result=False)
     session = _make_tx_session([pending_task, failed_task])
+    wait = pending_task.wait
+
+    def fail_sibling_during_wait(timeout: Optional[float] = None) -> bool:
+        result = wait(timeout)
+        failed_task.status = TaskStatus.ERROR
+        return result
+
+    pending_task.wait = fail_sibling_during_wait
 
     assert session.wait_complete(blocking=True) == WaitResult.FAILED
-    assert pending_task.wait_calls == []
+    assert pending_task.wait_calls == [0.25]
     assert failed_task.wait_calls == []
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/disaggregated/test_transceiver_bounded_polling.py` around
lines 421 - 428, Update
test_tx_session_blocking_wait_detects_failed_sibling_behind_pending_task so
failed_task starts in a non-error state and transitions to TaskStatus.ERROR
during pending_task’s first wait slice, allowing wait_complete(blocking=True) to
reach and validate the in-loop sibling failure recheck. Preserve the assertions
that the result is WaitResult.FAILED and both tasks’ wait-call behavior remains
correct.
tests/scripts/perf-sanity/disaggregated/gb300_deepseek-v4-pro-fp4_8k1k_con180_ctx3_dep4_gen1_dep32_eplb384_mtp3_ccb-NIXL.yaml (1)

70-70: 🩺 Stability & Availability | 🔵 Trivial

Note the reduced receive deadline for the high-concurrency workload.

kv_transfer_timeout_ms feeds rx_timeout_s in KvCacheTransceiverV2.__init__ (tensorrt_llm/_torch/disaggregation/transceiver.py line 108). The 10x reduction to 60 s tightens the receive deadline. The PR description states that the targeted run does not establish resolution of the concurrency-1760, 8-CTX-worker case. Under that load a cold NIXL link can exceed 60 s and the request then fails instead of completing late. Track a follow-up run at the original concurrency before this config is used as the perf-sanity baseline.

Also applies to: 101-101

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@tests/scripts/perf-sanity/disaggregated/gb300_deepseek-v4-pro-fp4_8k1k_con180_ctx3_dep4_gen1_dep32_eplb384_mtp3_ccb-NIXL.yaml`
at line 70, Restore kv_transfer_timeout_ms to its previous value for this
high-concurrency perf-sanity configuration, rather than using the reduced 60000
ms receive deadline. Apply the same correction to the additionally referenced
occurrence and retain the original timeout until the concurrency-1760,
8-CTX-worker follow-up run validates a shorter deadline.
tensorrt_llm/_torch/disaggregation/native/transfer.py (1)

1374-1390: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Remove the unreachable WaitResult.TIMEOUT handling. No wait_complete implementation returns WaitResult.TIMEOUT; remove the branch and timed_out plumbing from _ctx_consensus_outcome.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_torch/disaggregation/native/transfer.py` around lines 1374 -
1390, The _ctx_consensus_outcome flow still contains obsolete timeout handling.
Remove the unreachable WaitResult.TIMEOUT branch and all timed_out plumbing from
_ctx_consensus_outcome, while preserving the existing FAILED and COMPLETED
outcomes and auxiliary-task waiting behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tensorrt_llm/_torch/disaggregation/native/transfer.py`:
- Around line 1355-1373: Update the wait-slice handling in TxSession’s
blockAll/wait_complete flow so nonpositive or None _timeout_s values still use a
small positive polling interval instead of becoming an unbounded
task.wait(timeout=None). Preserve the existing wait loop and has_failed()
recheck, ensuring cancellation of TRANSFERRING tasks can reach the terminal
failure result.

In `@tests/scripts/perf-sanity/cache_transceiver_precheck/README.md`:
- Around line 80-86: Update every documented command in the README that assigns
LLM_MODELS_ROOT so the model-root placeholder is quoted, including both the
dry-run and SLURM examples; preserve the existing command structure and
arguments.

In `@tests/unittest/scripts/test_perf_submit.py`:
- Around line 136-140: Update
test_extract_pytest_command_env_rejects_malformed_export to use a valid, closed
outer pytestCommand export containing an unclosed payload quote, then assert
ValueError matches "cannot parse pytestCommand payload". Add this test to the
applicable CI and QA test lists.

---

Nitpick comments:
In `@tensorrt_llm/_torch/disaggregation/native/transfer.py`:
- Around line 1374-1390: The _ctx_consensus_outcome flow still contains obsolete
timeout handling. Remove the unreachable WaitResult.TIMEOUT branch and all
timed_out plumbing from _ctx_consensus_outcome, while preserving the existing
FAILED and COMPLETED outcomes and auxiliary-task waiting behavior.

In `@tests/scripts/perf-sanity/cache_transceiver_precheck/precheck_config.py`:
- Around line 132-139: Update precheck_prefix_lines with precise type
annotations for every parameter and its return value, and add a Google-style
docstring documenting all arguments—especially llm_models_root—and that the
function returns generated export lines. Keep the shared launch-script interface
behavior unchanged.

In
`@tests/scripts/perf-sanity/disaggregated/gb300_deepseek-v4-pro-fp4_8k1k_con180_ctx3_dep4_gen1_dep32_eplb384_mtp3_ccb-NIXL.yaml`:
- Line 70: Restore kv_transfer_timeout_ms to its previous value for this
high-concurrency perf-sanity configuration, rather than using the reduced 60000
ms receive deadline. Apply the same correction to the additionally referenced
occurrence and retain the original timeout until the concurrency-1760,
8-CTX-worker follow-up run validates a shorter deadline.

In `@tests/unittest/disaggregated/test_transceiver_bounded_polling.py`:
- Around line 421-428: Update
test_tx_session_blocking_wait_detects_failed_sibling_behind_pending_task so
failed_task starts in a non-error state and transitions to TaskStatus.ERROR
during pending_task’s first wait slice, allowing wait_complete(blocking=True) to
reach and validate the in-loop sibling failure recheck. Preserve the assertions
that the result is WaitResult.FAILED and both tasks’ wait-call behavior remains
correct.

In `@tests/unittest/others/test_cache_transceiver_precheck_run.py`:
- Around line 380-397: Clarify the event-list usage in
test_ctx_finish_wave_frees_only_after_block_all_returns_every_request by
discarding the unused free_events value from _ctx_finish_runner and asserting
the _free_all callback’s local events directly, or otherwise assert only the
runner-owned list without checking the discarded list.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 0c62c6c3-d848-439d-947f-9a0a1e3e5e7d

📥 Commits

Reviewing files that changed from the base of the PR and between 73efcee and b7bd98a.

📒 Files selected for processing (13)
  • jenkins/scripts/perf/local/submit.py
  • jenkins/scripts/perf/submit.py
  • tensorrt_llm/_torch/disaggregation/native/transfer.py
  • tensorrt_llm/_torch/disaggregation/transceiver.py
  • tests/scripts/perf-sanity/cache_transceiver_precheck/README.md
  • tests/scripts/perf-sanity/cache_transceiver_precheck/precheck_config.py
  • tests/scripts/perf-sanity/cache_transceiver_precheck/run_precheck.py
  • tests/scripts/perf-sanity/disaggregated/gb300_deepseek-v4-pro-fp4_8k1k_con180_ctx3_dep4_gen1_dep32_eplb384_mtp3_ccb-NIXL.yaml
  • tests/unittest/disaggregated/test_cache_transceiver_precheck_e2e.py
  • tests/unittest/disaggregated/test_transceiver_bounded_polling.py
  • tests/unittest/others/test_cache_transceiver_precheck_config.py
  • tests/unittest/others/test_cache_transceiver_precheck_run.py
  • tests/unittest/scripts/test_perf_submit.py

Comment thread tensorrt_llm/_torch/disaggregation/native/transfer.py
Comment thread tests/scripts/perf-sanity/cache_transceiver_precheck/README.md Outdated
Comment thread tests/unittest/scripts/test_perf_submit.py
Comment thread tests/scripts/perf-sanity/cache_transceiver_precheck/run_precheck.py Outdated
@chienchunhung
chienchunhung requested review from a team, nv-xtf and pcastonguay August 4, 2026 18:02
@chienchunhung
chienchunhung force-pushed the codex/nvbug-6480621-timeout-60s-ci branch from b7bd98a to f2d7cb6 Compare August 4, 2026 23:44
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

…precheck

Signed-off-by: Chien-Chun Hung <2679986+chienchunhung@users.noreply.github.com>
Signed-off-by: Chien-Chun Hung <2679986+chienchunhung@users.noreply.github.com>
@chienchunhung
chienchunhung force-pushed the codex/nvbug-6480621-timeout-60s-ci branch from f2d7cb6 to 1714136 Compare August 5, 2026 00:02
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
tests/unittest/others/test_cache_transceiver_precheck_run.py (2)

83-111: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a large exact-boundary case to the parametrization.

Only the 1024 case allocates the extra reserve page. 1024 is a multiple of tokens_per_block, so num_allocated is 9 while num_prompt_blocks is 8.

7408 is not a multiple of 128. num_allocated and num_prompt_blocks are both 58, so that case would still pass if the trim in _request_block_views were removed. Add a large exact-boundary length, such as 7424 (58 blocks, 59 allocated), to protect the boundary the stacked fix targets.

♻️ Proposed parametrization change
-@pytest.mark.parametrize(("prompt_len", "expected_blocks"), ((1024, 8), (7408, 58)))
+@pytest.mark.parametrize(("prompt_len", "expected_blocks"), ((1024, 8), (7408, 58), (7424, 58)))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/others/test_cache_transceiver_precheck_run.py` around lines 83
- 111, Extend the parametrization of
test_request_block_views_excludes_untransferred_speculative_page with a large
exact-boundary prompt length such as 7424 and expect 58 verified blocks. Keep
the existing 1024 and 7408 cases unchanged so the test covers both reserve-page
allocation and the large exact-boundary trim in _request_block_views.

454-464: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the DISAGG_TRANS_ERROR state branch.

Request 1 is in the failed list here, so ctx_finish_wave raises at the failed_pairs check. The later branch that inspects req.state == self.llm_request_state.DISAGG_TRANS_ERROR is never reached by any test in this file.

Add a case where block-all reports the rid as completed but the request state is the error state. That path also must retain pages.

💚 Proposed added test
def test_ctx_finish_wave_retains_pages_on_disagg_trans_error_state(monkeypatch):
    runner, events = _ctx_finish_runner(monkeypatch, lambda _n: ([101], []))
    reqs = {0: types.SimpleNamespace(py_request_id=101, state="error")}

    with pytest.raises(rp._TransferError, match=r"ctx DISAGG_TRANS_ERROR on pairs \[0\]"):
        runner.ctx_finish_wave(reqs)

    assert events == []
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/others/test_cache_transceiver_precheck_run.py` around lines
454 - 464, Add a test alongside
test_ctx_finish_wave_retains_pages_when_request_failed that makes block-all
report the request as completed while its state is DISAGG_TRANS_ERROR, using
_ctx_finish_runner with no failed IDs and a request for pair 0. Assert
ctx_finish_wave raises the DISAGG_TRANS_ERROR-specific _TransferError and that
events remains empty, confirming pages are retained.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/unittest/others/test_cache_transceiver_precheck_run.py`:
- Around line 83-111: Extend the parametrization of
test_request_block_views_excludes_untransferred_speculative_page with a large
exact-boundary prompt length such as 7424 and expect 58 verified blocks. Keep
the existing 1024 and 7408 cases unchanged so the test covers both reserve-page
allocation and the large exact-boundary trim in _request_block_views.
- Around line 454-464: Add a test alongside
test_ctx_finish_wave_retains_pages_when_request_failed that makes block-all
report the request as completed while its state is DISAGG_TRANS_ERROR, using
_ctx_finish_runner with no failed IDs and a request for pair 0. Assert
ctx_finish_wave raises the DISAGG_TRANS_ERROR-specific _TransferError and that
events remains empty, confirming pages are retained.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 9fc46729-afee-487d-9cda-fe1261acdbf7

📥 Commits

Reviewing files that changed from the base of the PR and between 1982523 and 1714136.

📒 Files selected for processing (13)
  • jenkins/scripts/perf/local/submit.py
  • jenkins/scripts/perf/submit.py
  • tensorrt_llm/_torch/disaggregation/native/transfer.py
  • tensorrt_llm/_torch/disaggregation/transceiver.py
  • tests/scripts/perf-sanity/cache_transceiver_precheck/README.md
  • tests/scripts/perf-sanity/cache_transceiver_precheck/precheck_config.py
  • tests/scripts/perf-sanity/cache_transceiver_precheck/run_precheck.py
  • tests/scripts/perf-sanity/disaggregated/gb300_deepseek-v4-pro-fp4_8k1k_con180_ctx3_dep4_gen1_dep32_eplb384_mtp3_ccb-NIXL.yaml
  • tests/unittest/disaggregated/test_cache_transceiver_precheck_e2e.py
  • tests/unittest/disaggregated/test_transceiver_bounded_polling.py
  • tests/unittest/others/test_cache_transceiver_precheck_config.py
  • tests/unittest/others/test_cache_transceiver_precheck_run.py
  • tests/unittest/scripts/test_perf_submit.py
🚧 Files skipped from review as they are similar to previous changes (11)
  • jenkins/scripts/perf/local/submit.py
  • tests/scripts/perf-sanity/cache_transceiver_precheck/precheck_config.py
  • tensorrt_llm/_torch/disaggregation/native/transfer.py
  • jenkins/scripts/perf/submit.py
  • tests/unittest/disaggregated/test_cache_transceiver_precheck_e2e.py
  • tests/scripts/perf-sanity/cache_transceiver_precheck/README.md
  • tests/unittest/scripts/test_perf_submit.py
  • tensorrt_llm/_torch/disaggregation/transceiver.py
  • tests/scripts/perf-sanity/disaggregated/gb300_deepseek-v4-pro-fp4_8k1k_con180_ctx3_dep4_gen1_dep32_eplb384_mtp3_ccb-NIXL.yaml
  • tests/scripts/perf-sanity/cache_transceiver_precheck/run_precheck.py
  • tests/unittest/disaggregated/test_transceiver_bounded_polling.py

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63870 [ run ] triggered by Bot. Commit: 1714136 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63870 [ run ] completed with state SUCCESS. Commit: 1714136
/LLM/main/L0_MergeRequest_PR pipeline #51810 completed with status: 'FAILURE'

CI Report

⚠️ Multi-GPU Label Required:
Multi-GPU tests require the ci: full pre-merge approved label on this PR. Ask a member of NVIDIA/trt-llm-ci-approvers to add the label, then re-trigger CI with the same bot command (no rebase needed).

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@BowenFu

BowenFu commented Aug 5, 2026

Copy link
Copy Markdown

The tensorrt_llm/ portion of this PR is byte-identical to #17223 — I diffed the product hunks of both PR diffs and they match exactly. This PR is #17223 plus the kv_transfer_timeout_ms: 600000 → 60000 revert in the GB300 yaml.

That matters because the two are in very different review states. #17223 is [fix], has zero approvals, and carries my open findings. This one is [test], has two approvals and no open threads — so the disagg blocking-wait change would land here under a title that only advertises a timeout revert. Please either drop transfer.py/transceiver.py from this PR and let #17223 carry them, or bring the findings over. The two that matter:

  1. WaitResult.TIMEOUT becomes dead repo-wide. Both return WaitResult.TIMEOUT sites are removed from TxSession.wait_complete, but the consumer arm at transceiver.py:703 is kept with its log demoted warningdebug. Nothing can reach it, timed_out is permanently empty, and it is still threaded through _ctx_consensus_outcome. Delete the branch rather than quieting it.

  2. The blocking path now has no deadline. while not task.wait(wait_slice_s): if self.has_failed(): return FAILED exits only on completion or a reported failure. The diagnosis in the description says _timeout_s is the wrong bound and kv_transfer_timeout_ms is the right one — but the fix removes the bound instead of switching to it. A peer that stalls without erroring hangs forever.

Separately, jenkins/scripts/perf/submit.py and cache_transceiver_precheck/precheck_config.py collide with #17121, which is also review-ready:

  • Both add a parser for the same thing to the same file — extract_pytest_command_env() here, _get_pytest_command_env_var() there — with different semantics (yours stops at the first non-KEY= token and raises on every miss; theirs scans all tokens and returns None).
  • precheck_prefix_lines() gains llm_models_root in both, but here it is a required positional before stage_name and there it is optional after it.
  • The inline comments give directly opposite instructions: yours says "Keep this as a top-level assignment. shlex.quote() is not safe when nested inside the double-quoted pytestCommand exports below"; [https://nvbugs/6541356][fix] align cache transceiver harness setup #17121 says to quote the complete assignment as an export value and nests it. One of you is wrong about the quoting.

Worth sorting out between you before either merges. Also: _resolve_model_prefs now fails fast with "refusing to assume V1" — a real behavior change in the precheck that the [test] title doesn't cover.

@brnguyen2 brnguyen2 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving — the comments below are optional touch-ups, not blockers.

Reviewed the prerequisite commit as the real content; the YAML edit itself is fine.

One framing note for the PR description: kv_transfer_timeout_ms and the sender wait slice are different knobs. The YAML value feeds rx_timeout_s and the py_executor request-cancel deadline (py_executor.py:6159); the sender's slice is kv_transfer_sender_future_timeout_ms (default 1000ms). So the revert restores the 60s request cancellation deadline, and it's safe now because wait_complete observes cancellation between slices rather than mistaking a slice expiry for completion. Worth saying that way in the commit message — "600s → 60s" alone reads like the thing that was failing is being re-enabled unchanged.

The main leftover is that TxSession.wait_complete can no longer return TIMEOUT, which leaves dead plumbing in check_context_transfer_status and removes the last diagnostic for a wedged sender (details inline). Otherwise the ownership contract is clearly stated and the unit tests cover the cases that matter — cancel-between-slices, failed sibling behind a pending task, and retain-on-failure for both ctx and gen.

for task in self.kv_tasks:
if not task.wait(timeout=self._timeout_s):
return WaitResult.TIMEOUT
while not task.wait(timeout=wait_slice_s):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(to be fixed in PR #17223, not here) This loop has no diagnostic at all. Previously a stuck task produced a TIMEOUT and a warning; now it spins on 1s slices silently. The only escape is the executor's request-cancel deadline (kv_transfer_timeout_ms, default 60000) — if a deployment sets that to null, check_context_transfer_status(None) blocks the executor thread forever with nothing in the log.

Suggest logging inside the loop on an escalating cadence, e.g. warn once past N slices with the elapsed time and rid, so a wedged NIXL write is diagnosable from a CI log without a stack dump.

@@ -703,8 +703,9 @@ def check_context_transfer_status(
elif result is None:
continue
elif result == WaitResult.TIMEOUT:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(to be fixed in PR #17223, not here) This branch is now unreachable for TxSession: the blocking path loops until terminal and the non-blocking path returns None, so wait_complete never yields TIMEOUT. That makes timed_out, its _ctx_consensus_outcome argument, and this (now debug-level) message dead code.

Either delete the branch and the timed_out plumbing, or keep it and make wait_complete actually return TIMEOUT after some bounded number of slices. Leaving a permanently-false branch that also happens to be the only place a stalled sender was ever logged is the worst of both.

if not self.aux_task.wait(timeout=self._timeout_s):
return WaitResult.TIMEOUT
if self._need_aux:
if self.aux_task is None:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(to be fixed in PR #17223, not here) A blocking=True call returning None is surprising for the caller: check_context_transfer_status hits elif result is None: continue, so the rid stays in _send_sessions and block-all returns claiming it drained everything. Is aux_task guaranteed to be set before the first wait_complete when _need_aux is true? If it's a transient window this is fine but should say so; if it can persist, this is a silent stuck-request path (the precheck catches it as missing, production won't).

# block boundary those tokens allocate an additional page, but the
# transceiver intentionally trims its slice to prompt_len blocks.
# Verify the same payload range instead of the untransferred page.
valid = [b for b in blocks if b >= 0][:num_prompt_blocks]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(to be fixed in PR #17223, not here) The [:num_prompt_blocks] slice silently absorbs the under-allocated case too: if the KV manager hands back fewer valid blocks than the prompt needs — a real bug this precheck exists to catch — verification just checks fewer blocks and passes.

Add an explicit check, e.g. if len(valid) < num_prompt_blocks: raise/return a mismatch detail naming the layer and the counts. Only the extra trailing speculative page should be trimmed.

key, value = token.split("=", 1)
if key == name:
return value
raise ValueError(f"pytestCommand does not set leading environment variable {name}")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(to be fixed in PR #17223, not here) This raises when LLM_MODELS_ROOT isn't a leading assignment in pytestCommand. Today getPytestBaseCommandLine (L0_Test.groovy:1358) always emits it third, so it works — but this turns a precheck-config detail into a hard abort of the whole disagg perf submission if that Groovy list is ever reordered or the var moves into envVarsToExport. Consider falling back to os.environ.get("LLM_MODELS_ROOT") before raising, or at least referencing the Groovy site in the error message so the next person knows where to look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants